﻿using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace vis_client
{
	public class ServerConnection
	{
		protected Socket _Socket = null;
		protected Thread _CommThread = null;
		protected bool _KeepCommunicating = true;

		protected Stopwatch _Stopwatch;
		protected int _NumSteps;

		protected Byte[] _MetadataBuffer = null;
		protected Byte[] _ImageBuffer = null;

		public ServerConnection(String serverAddr, int port)
		{
			IPHostEntry hostEntry = Dns.GetHostEntry(serverAddr);
			foreach (IPAddress addr in hostEntry.AddressList)
			{
				IPEndPoint ipe = new IPEndPoint(addr, port);
				try
				{
					Socket s = new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
					s.ReceiveTimeout = 666;
					s.Connect(ipe);
					if (s.Connected)
					{
						_Socket = s;
						//_Socket.ReceiveBufferSize = 2000000;
						break;
					}
				}
				catch (Exception) { }
			}

			if (this.IsConnected)
			{
				_CommThread = new Thread(new ThreadStart(this.ThreadLoop));
				_CommThread.Start();
			}
		}

		public bool IsConnected
		{
			get { return _Socket != null; }
		}

		public void Close()
		{
			_KeepCommunicating = false;
			_CommThread.Join();
			_Socket.Close();
			_CommThread = null;
			_Socket = null;
		}

		protected void ThreadLoop()
		{
			_Stopwatch = new Stopwatch();
			_Stopwatch.Start();
			_NumSteps = 0;

			while (_KeepCommunicating)
			{
				this.GetFrame();
				_NumSteps++;

				if (_NumSteps % 2500 == 0)
				{
					double avgStepTime = _Stopwatch.ElapsedMilliseconds / 2500.0;
					Debug.WriteLine("Receiving " + (1000.0 / avgStepTime).ToString("n4") + " steps per second");
					_Stopwatch.Reset();
					_Stopwatch.Start();
				}
			}

			this.CloseSession();
		}

		protected void GetFrame()
		{
			try
			{
				if (_MetadataBuffer == null || _MetadataBuffer.Length != 8)
					_MetadataBuffer = new byte[8];

				int received = 0;
				while (_KeepCommunicating && received < 8)
				{
					try
					{
						received = _Socket.Receive(_MetadataBuffer);
					}
					catch (SocketException) { }
				}

				if (_KeepCommunicating)
				{
					int width = BitConverter.ToInt32(_MetadataBuffer, 0);
					int height = BitConverter.ToInt32(_MetadataBuffer, 4);

					if (width > 0 && height > 0)
					{
						if (_ImageBuffer == null || _ImageBuffer.Length != width * height * 4)
							_ImageBuffer = new byte[width * height * 4];

						received = 0;
						while (_KeepCommunicating && received < _ImageBuffer.Length)
						{
							int result = 0;
							try
							{
								result = _Socket.Receive(_ImageBuffer, received,
									_ImageBuffer.Length - received, SocketFlags.None);
							}
							catch (SocketException) { }

							if (result > 0)
								received += result;
						}

						SimData.UpdateFrame(_ImageBuffer, width, height);
					}
				}
			}
			catch (SocketException) { }
		}

		protected void CloseSession()
		{
			if (_Socket != null)
			{
				try
				{
					_Socket.Send(Encoding.ASCII.GetBytes("close-session"));
				}
				catch (SocketException) { }
			}
		}
	}
}
